Working with HashMap and LinkedHashMap in Java
Course: Core Java Training
Topic: Working with HashMap and LinkedHashMap
Course Link: Core Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy Official Website
1. Introduction to HashMap and LinkedHashMap
Java provides the Map interface to store data as key-value pairs. Each key identifies a value, allowing applications to retrieve, update, or remove information using that key. Maps are useful for employee records, product catalogs, student information, configuration settings, and many other applications.
HashMap and LinkedHashMap are two commonly used implementations of the Map interface. Both allow efficient key-based operations and store at most one mapping for each key. Their main difference is iteration order.
- HashMap: Does not guarantee the order in which entries are iterated.
- LinkedHashMap: Maintains a predictable iteration order, normally insertion order.
Choosing between these implementations depends on whether predictable ordering is important to the application.
2. Learning Objectives
- Understand the Map interface and key-value data structures.
- Learn the features and working principles of HashMap.
- Learn how LinkedHashMap maintains iteration order.
- Create, insert, retrieve, update, and remove map entries.
- Use methods such as
put(), get(), getOrDefault(), and containsKey().
- Understand null handling, duplicate keys, and key equality.
- Compare HashMap and LinkedHashMap performance and behavior.
- Apply both implementations to practical Java programming problems.
3. What Is the Map Interface?
The Map interface belongs to the java.util package. It represents associations between keys and values. Keys must be unique according to the map's equality rules, but multiple keys can map to equal values.
For example, a college application may store student roll numbers as keys and student names as values.
| Roll Number (Key) |
Student Name (Value) |
| 101 |
Amit |
| 102 |
Neha |
| 103 |
Ravi |
Using a roll number as a key allows the application to retrieve a student's name without searching every entry manually.
Important Characteristics of Map
- Each key maps to at most one value at a time.
- Different keys may map to the same value.
- Adding an existing key replaces its previous value.
- Keys and values can be accessed through map methods and views.
- Map does not extend the Collection interface, although it is part of the Java Collections Framework.
4. What Is HashMap?
HashMap is a Map implementation that uses hashing to organize key-value entries. It provides expected constant-time performance for basic operations such as put() and get() when hash values are distributed suitably.
Main Features of HashMap
- Stores key-value pairs.
- Does not guarantee insertion or sorted iteration order.
- Allows one null key and multiple null values.
- Replaces the value associated with a key when that key is inserted again.
- Provides expected O(1) performance for common operations under suitable hashing conditions.
- Is not synchronized by default.
- Uses
hashCode() and equals() to support key lookup.
5. Creating a HashMap
Import the Map and HashMap classes from the java.util package. Generic types specify the key and value types.
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
Map<Integer, String> students = new HashMap<>();
System.out.println(students);
System.out.println("Size: " + students.size());
}
}
Output:
{}
Size: 0
The declaration Map<Integer, String> means that each key is an Integer and each value is a String. Declaring the variable using the Map interface makes it easier to replace the implementation later.
6. Adding Entries with put()
The put() method inserts a new key-value mapping or replaces the value associated with an existing key.
import java.util.HashMap;
import java.util.Map;
public class PutExample {
public static void main(String[] args) {
Map<Integer, String> students = new HashMap<>();
students.put(101, "Amit");
students.put(102, "Neha");
students.put(103, "Ravi");
System.out.println(students);
}
}
Possible Output:
{101=Amit, 102=Neha, 103=Ravi}
This output illustrates the entries; HashMap does not guarantee that the displayed order will match the insertion order.
Adding an Existing Key
import java.util.HashMap;
import java.util.Map;
public class UpdateExistingKeyExample {
public static void main(String[] args) {
Map<Integer, String> students = new HashMap<>();
students.put(101, "Amit");
students.put(102, "Neha");
students.put(101, "Amit Kumar");
System.out.println(students.get(101));
System.out.println(students.size());
}
}
Output:
Amit Kumar
2
Adding key 101 again replaces its previous value instead of creating another entry. The map still contains two keys.
7. Retrieving Values with get()
The get() method returns the value associated with a key. If the key is not present, it returns null.
import java.util.HashMap;
import java.util.Map;
public class GetExample {
public static void main(String[] args) {
Map<Integer, String> employees = new HashMap<>();
employees.put(201, "Priya");
employees.put(202, "Karan");
System.out.println(employees.get(201));
System.out.println(employees.get(999));
}
}
Output:
Priya
null
A null result can mean that a key is absent or that the key is explicitly mapped to null. Use containsKey() when this distinction matters.
8. Important HashMap Methods
| Method |
Description |
Example |
put(key, value) |
Adds a mapping or replaces the value for a key. |
map.put(101, "Amit"); |
get(key) |
Returns the associated value or null. |
map.get(101); |
getOrDefault(key, defaultValue) |
Returns the mapped value or the supplied default when the key is absent. |
map.getOrDefault(999, "Unknown"); |
containsKey(key) |
Checks whether the key exists. |
map.containsKey(101); |
containsValue(value) |
Checks whether a value exists. |
map.containsValue("Amit"); |
remove(key) |
Removes the mapping for a key. |
map.remove(101); |
size() |
Returns the number of mappings. |
map.size(); |
isEmpty() |
Checks whether the map has no mappings. |
map.isEmpty(); |
putIfAbsent(key, value) |
Adds a mapping when the key is absent or currently mapped to null. |
map.putIfAbsent(101, "Amit"); |
clear() |
Removes all mappings. |
map.clear(); |
9. Checking Keys and Values
The methods containsKey() and containsValue() help determine whether a key or value exists in the map.
import java.util.HashMap;
import java.util.Map;
public class ContainsExample {
public static void main(String[] args) {
Map<Integer, String> employees = new HashMap<>();
employees.put(301, "Meera");
employees.put(302, "Arjun");
System.out.println(employees.containsKey(301));
System.out.println(employees.containsKey(999));
System.out.println(employees.containsValue("Arjun"));
}
}
Output:
true
false
true
Key checks are generally efficient under suitable hashing conditions. Checking whether a value exists typically requires examining entries and is O(n) in the general case.
10. Iterating Through a HashMap
Java provides several ways to iterate through map entries, keys, and values.
Using entrySet()
The entrySet() method is useful when both the key and value are needed during iteration.
import java.util.HashMap;
import java.util.Map;
public class EntrySetExample {
public static void main(String[] args) {
Map<Integer, String> students = new HashMap<>();
students.put(101, "Amit");
students.put(102, "Neha");
students.put(103, "Ravi");
for (Map.Entry<Integer, String> entry
: students.entrySet()) {
System.out.println(
entry.getKey() + " : " + entry.getValue()
);
}
}
}
Example Output:
101 : Amit
102 : Neha
103 : Ravi
The displayed order is only illustrative; HashMap iteration order is not guaranteed.
Using keySet()
for (Integer id : students.keySet()) {
System.out.println(id);
}
This approach is suitable when only keys are required.
Using values()
for (String name : students.values()) {
System.out.println(name);
}
This approach is suitable when only values are needed. Duplicate values may appear because different keys can map to the same value.
Using forEach()
students.forEach((id, name) ->
System.out.println(id + " : " + name)
);
The forEach() method provides a concise way to process each mapping. It does not make HashMap iteration ordered.
11. What Is LinkedHashMap?
LinkedHashMap is a Map implementation that combines hash-based lookup with a linked structure that maintains a predictable iteration order.
By default, LinkedHashMap preserves insertion order. When an existing key is updated, its position in insertion order normally remains unchanged.
Main Features of LinkedHashMap
- Stores key-value mappings and prevents duplicate keys.
- Maintains insertion order by default.
- Can optionally maintain access order instead of insertion order.
- Allows one null key and multiple null values.
- Typically provides expected O(1) performance for basic operations under suitable hashing conditions.
- Uses additional memory for linked-order information compared with HashMap.
- Is not synchronized by default.
12. Creating a LinkedHashMap
LinkedHashMap belongs to the java.util package and can be used through the Map interface.
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapExample {
public static void main(String[] args) {
Map<Integer, String> students =
new LinkedHashMap<>();
students.put(103, "Ravi");
students.put(101, "Amit");
students.put(102, "Neha");
System.out.println(students);
}
}
Output:
{103=Ravi, 101=Amit, 102=Neha}
The entries appear in insertion order: 103, 101, and then 102.
13. Understanding Insertion Order
Insertion order means that entries are iterated in the order their keys were first inserted into the map. Updating the value of an existing key does not normally move that entry to the end.
import java.util.LinkedHashMap;
import java.util.Map;
public class InsertionOrderExample {
public static void main(String[] args) {
Map<Integer, String> employees =
new LinkedHashMap<>();
employees.put(1, "Amit");
employees.put(2, "Neha");
employees.put(3, "Ravi");
employees.put(2, "Neha Sharma");
System.out.println(employees);
}
}
Output:
{1=Amit, 2=Neha Sharma, 3=Ravi}
The value for key 2 changes, but its position remains between keys 1 and 3.
14. HashMap vs LinkedHashMap
| Feature |
HashMap |
LinkedHashMap |
| Ordering |
No guaranteed iteration order |
Insertion order by default |
| Key uniqueness |
Yes |
Yes |
| Null key |
Allows one null key |
Allows one null key |
| Null values |
Allowed |
Allowed |
| Basic operation performance |
Expected O(1) under suitable hashing conditions |
Expected O(1) under suitable hashing conditions |
| Memory overhead |
Generally lower |
Generally higher due to linked-order information |
| Access-order mode |
Not provided |
Supported through a constructor option |
| Typical use |
General-purpose key-value storage |
Key-value storage with predictable iteration order |
15. Creating a LinkedHashMap with Access Order
LinkedHashMap supports a constructor parameter that enables access-order iteration. When enabled, entries are ordered from least recently accessed to most recently accessed. This behavior can be useful for cache implementations.
import java.util.LinkedHashMap;
import java.util.Map;
public class AccessOrderExample {
public static void main(String[] args) {
Map<Integer, String> cache =
new LinkedHashMap<>(16, 0.75f, true);
cache.put(1, "One");
cache.put(2, "Two");
cache.put(3, "Three");
cache.get(1);
System.out.println(cache);
}
}
Output:
{2=Two, 3=Three, 1=One}
After key 1 is accessed, it moves to the most recently accessed position in the iteration order. In access-order mode, certain retrieval operations can change the iteration order, so modifying the map while iterating requires care.
16. Using LinkedHashMap to Build a Simple LRU Cache
An LRU (Least Recently Used) cache removes the least recently accessed entry when the cache reaches its capacity. LinkedHashMap can support a simple LRU-style implementation through access-order mode and the removeEldestEntry() method.
import java.util.LinkedHashMap;
import java.util.Map;
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(16, 0.75f, true);
if (capacity < 1) {
throw new IllegalArgumentException(
"Capacity must be positive"
);
}
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(
Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
public class LRUCacheExample {
public static void main(String[] args) {
LRUCache<Integer, String> cache =
new LRUCache<>(3);
cache.put(1, "One");
cache.put(2, "Two");
cache.put(3, "Three");
cache.get(1);
cache.put(4, "Four");
System.out.println(cache);
}
}
Output:
{3=Three, 1=One, 4=Four}
The cache has capacity three. Accessing key 1 makes it recently used. When key 4 is inserted, key 2 is the least recently accessed entry and is removed.
This example demonstrates the basic idea of an LRU cache. Production caches may require additional features such as concurrency control, expiration, size limits based on memory, or more advanced eviction policies.
17. Handling Null Keys and Values
Both HashMap and LinkedHashMap allow one null key and multiple null values. However, null values can make it important to distinguish between a missing key and a key explicitly mapped to null.
import java.util.HashMap;
import java.util.Map;
public class NullHandlingExample {
public static void main(String[] args) {
Map<String, String> data = new HashMap<>();
data.put(null, "Unknown Key");
data.put("A", null);
System.out.println(data.containsKey("A"));
System.out.println(data.get("A"));
System.out.println(data.containsKey("B"));
}
}
Output:
true
null
false
Both get("A") and get("B") could return null, but containsKey() distinguishes the two cases.
18. Understanding equals() and hashCode()
HashMap and LinkedHashMap rely on the hash code and equality behavior of keys. A key's hashCode() helps determine where the entry is stored, while equals() helps identify whether keys are logically equivalent.
Important Rules
- If two objects are equal according to
equals(), they must return the same hash code.
- Unequal objects may have the same hash code; this is called a hash collision.
- Collisions are handled internally by the map implementation.
- Key fields used by equality and hashing should not be changed while the object is being used as a map key.
- Custom key classes should implement
equals() and hashCode() consistently.
Example: Using a Custom Object as a Key
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
class EmployeeKey {
private final int id;
public EmployeeKey(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof EmployeeKey)) {
return false;
}
EmployeeKey other = (EmployeeKey) obj;
return id == other.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public class CustomKeyExample {
public static void main(String[] args) {
Map<EmployeeKey, String> employees =
new HashMap<>();
employees.put(new EmployeeKey(101), "Amit");
System.out.println(
employees.get(new EmployeeKey(101))
);
}
}
Output:
Amit
Although the lookup uses a different EmployeeKey object, the two objects are logically equal because their IDs match and their equality and hash-code implementations are consistent.
19. Updating and Removing Map Entries
Map provides several methods for changing or removing mappings.
import java.util.HashMap;
import java.util.Map;
public class UpdateRemoveExample {
public static void main(String[] args) {
Map<Integer, String> employees = new HashMap<>();
employees.put(101, "Amit");
employees.put(102, "Neha");
employees.replace(101, "Amit Sharma");
employees.remove(102);
System.out.println(employees);
}
}
Output:**
{101=Amit Sharma}
The replace() method updates an existing mapping, while remove() deletes the specified mapping. As this example uses HashMap, the iteration order is not guaranteed.
20. Counting Word Frequency with HashMap
A common use of HashMap is counting how frequently each word occurs in a document. Each word is a key, and its frequency is the associated value.
import java.util.HashMap;
import java.util.Map;
public class WordFrequencyExample {
public static void main(String[] args) {
String text = "java code java map code java";
Map<String, Integer> frequency = new HashMap<>();
for (String word : text.split(" ")) {
frequency.put(
word,
frequency.getOrDefault(word, 0) + 1
);
}
System.out.println(frequency);
}
}
Output:
{java=3, code=2, map=1}
The order shown is illustrative. The counts indicate that java occurs three times, code occurs twice, and map occurs once. For predictable word order in the output, a LinkedHashMap could be used instead.
21. Using LinkedHashMap for Ordered Data
LinkedHashMap is helpful when records should be displayed in the same order they were first added. This can be useful for menus, ordered settings, activity summaries, or data that needs stable iteration order.
import java.util.LinkedHashMap;
import java.util.Map;
public class OrderedSettingsExample {
public static void main(String[] args) {
Map<String, String> settings =
new LinkedHashMap<>();
settings.put("language", "English");
settings.put("theme", "Dark");
settings.put("notifications", "Enabled");
settings.forEach((key, value) ->
System.out.println(key + " = " + value)
);
}
}
Output:
language = English
theme = Dark
notifications = Enabled
LinkedHashMap is a useful choice when the order of presentation matters and a key-value structure is needed.
22. Performance and Memory Considerations
HashMap and LinkedHashMap generally provide expected constant-time lookup and update operations when keys are distributed suitably across the hash table.
| Operation |
HashMap |
LinkedHashMap |
| put() |
Expected O(1) |
Expected O(1) |
| get() |
Expected O(1) |
Expected O(1) |
| remove() |
Expected O(1) |
Expected O(1) |
| containsKey() |
Expected O(1) |
Expected O(1) |
| containsValue() |
O(n) in general |
O(n) in general |
| Iteration |
Depends on table capacity and number of entries |
Typically proportional to the number of entries |
| Memory |
Generally lower overhead |
Extra links are maintained to preserve iteration order |
These are typical performance characteristics, not a guarantee for every workload. Hash collisions, resizing, key behavior, memory pressure, and access patterns can affect actual performance.
23. Thread Safety and Concurrent Access
HashMap and LinkedHashMap are not synchronized by default. They should not be used as though they provide automatic thread safety when multiple threads modify the same map concurrently.
For applications with concurrent access, consider these alternatives based on the required behavior:
- ConcurrentHashMap: Useful for concurrent key-value storage and retrieval. It does not allow null keys or null values.
- Collections.synchronizedMap(): Wraps a map with synchronized access. Iteration still requires following the wrapper's synchronization guidance.
- ConcurrentSkipListMap: Useful when concurrent access and sorted key order are both required.
Choose the concurrency strategy based on the application's requirements. A concurrent map does not automatically make a sequence of multiple operations atomic.
24. Common Mistakes and How to Avoid Them
| Mistake |
Why It Is a Problem |
Solution |
| Assuming HashMap preserves insertion order |
Iteration order is not guaranteed. |
Use LinkedHashMap when insertion order matters. |
| Expecting duplicate keys |
A key can have only one mapping at a time. |
Use a collection as the value if one key must represent multiple items. |
| Assuming get() returning null always means the key is absent |
The key may exist with a null value. |
Check containsKey() when the distinction matters. |
| Using mutable objects as keys carelessly |
Changing fields used by hashCode() or equals() can make lookup unreliable. |
Prefer immutable keys or keep equality-related state unchanged. |
| Forgetting equals() and hashCode() |
Custom keys may not behave according to their intended logical identity. |
Implement both methods consistently. |
| Modifying a map during iteration without care |
Structural changes may trigger ConcurrentModificationException in ordinary iterators. |
Use supported iterator operations or perform modifications outside the iteration. |
| Using ordinary HashMap for concurrent mutation |
It is not thread-safe by default. |
Use appropriate synchronization or a concurrent implementation. |
| Choosing LinkedHashMap without needing order |
It maintains additional links and consumes extra memory. |
Use HashMap if ordering is unnecessary. |
25. Best Practices for HashMap and LinkedHashMap
- Declare map variables using the Map interface when possible.
- Use meaningful generic types such as
Map<Integer, Employee>.
- Choose HashMap for general-purpose key-value storage when iteration order is unimportant.
- Choose LinkedHashMap when predictable iteration order is needed.
- Use access-order LinkedHashMap when implementing a suitable LRU-style design.
- Implement equals() and hashCode() correctly for custom key classes.
- Prefer immutable key objects or avoid changing fields used for equality and hashing.
- Use
getOrDefault() to provide a fallback value when a key is absent.
- Use
computeIfAbsent() when a value should be created only if a key has no non-null mapping.
- Consider expected data size when selecting an initial capacity for a large map.
- Use concurrent collections when multiple threads need shared access.
- Test the implementation with realistic data before making performance decisions.
26. Practice Exercises
- Create a HashMap that stores five employee IDs and employee names.
- Retrieve an employee name using an employee ID.
- Update the value associated with an existing key and print the new value.
- Check whether a particular key exists using containsKey().
- Remove an entry and print the updated map size.
- Create a LinkedHashMap and verify that iteration follows insertion order.
- Store product IDs and product prices in a HashMap.
- Count the frequency of words in a sentence using HashMap.
- Use LinkedHashMap in access-order mode and observe how reading a key changes iteration order.
- Build a simple LRU cache by extending LinkedHashMap and overriding removeEldestEntry().
- Create a custom key class and implement equals() and hashCode() correctly.
- Explain when ConcurrentHashMap would be more appropriate than HashMap.
27. Mini Project: Student Record Management System
Objective: Create a simple application that stores student records using their roll numbers as keys.
Requirements:
- Store student roll numbers and names in a LinkedHashMap.
- Add new student records.
- Retrieve a student by roll number.
- Update an existing student's name.
- Remove a student record.
- Display all records in insertion order.
import java.util.LinkedHashMap;
import java.util.Map;
public class StudentRecordSystem {
public static void main(String[] args) {
Map<Integer, String> students =
new LinkedHashMap<>();
students.put(101, "Amit");
students.put(102, "Neha");
students.put(103, "Ravi");
System.out.println(
"Student 102: " + students.get(102)
);
students.put(102, "Neha Sharma");
students.remove(103);
System.out.println("All student records:");
students.forEach((rollNo, name) ->
System.out.println(rollNo + " : " + name)
);
}
}
Output:
Student 102: Neha
All student records:
101 : Amit
102 : Neha Sharma
This project demonstrates key-based lookup, updating, removal, and insertion-order iteration. The LinkedHashMap ensures that the remaining records are displayed in the order their keys were first inserted.
28. Interview Questions and Answers
Q1. What is HashMap in Java?
Answer: HashMap is a Map implementation that stores key-value pairs using hashing and does not guarantee iteration order.
Q2. What is LinkedHashMap?
Answer: LinkedHashMap is a Map implementation that maintains predictable iteration order, normally insertion order.
Q3. What is the main difference between HashMap and LinkedHashMap?
Answer: HashMap does not guarantee iteration order, while LinkedHashMap maintains insertion order by default or access order when configured.
Q4. Can HashMap contain duplicate keys?
Answer: No. Inserting a mapping for an existing key replaces its previous value.
Q5. Can HashMap store null values?
Answer: Yes. HashMap permits one null key and multiple null values. LinkedHashMap has the same null-handling behavior.
Q6. What happens when put() is called with an existing key?
Answer: The value associated with that key is replaced. The map does not create a second mapping for the same key.
Q7. What is the role of hashCode() and equals()?
Answer: hashCode() helps determine the hash-table location, while equals() helps determine whether keys are logically equal. Both must be implemented consistently for custom key classes.
Q8. What is access-order LinkedHashMap?
Answer: It is a LinkedHashMap configured to order entries from least recently accessed to most recently accessed, which is useful for LRU-style cache designs.
Q9. Are HashMap and LinkedHashMap thread-safe?
Answer: No. They are not synchronized by default. ConcurrentHashMap or suitable synchronization may be needed for concurrent access.
Q10. What is the average time complexity of HashMap get()?
Answer: It is expected O(1) under suitable hashing conditions, although collisions and other factors can affect performance.
Q11. Why might LinkedHashMap use more memory than HashMap?
Answer: LinkedHashMap maintains additional links between entries to preserve the configured iteration order.
Q12. What is the difference between keySet(), values(), and entrySet()?
Answer: keySet() provides the keys, values() provides the values, and entrySet() provides key-value entries. These are backed views of the map.
29. Quick Revision Checklist
- Map stores key-value pairs.
- Keys are unique; values do not have to be unique.
- HashMap does not guarantee iteration order.
- LinkedHashMap maintains insertion order by default.
- LinkedHashMap can also use access-order iteration.
- Both implementations permit one null key and multiple null values.
- put() inserts or replaces a mapping.
- get() retrieves a value; containsKey() checks whether a key exists.
- entrySet() is useful when both keys and values are required.
- Custom key classes need consistent equals() and hashCode() implementations.
- Both implementations are not synchronized by default.
- Choose HashMap when order is unnecessary and LinkedHashMap when predictable order matters.
30. Conclusion
HashMap and LinkedHashMap are important implementations in the Java Collections Framework. They make it possible to store and retrieve information efficiently using keys rather than relying on sequential searches through a list.
HashMap is a suitable general-purpose choice when iteration order does not matter. LinkedHashMap is preferable when predictable insertion order is required, and its access-order mode can support simple LRU-style cache designs.
Understanding map methods, key equality, hash codes, iteration behavior, null handling, performance, and concurrency helps developers select the right implementation for real-world applications.
Continue learning with the Core Java Training Course, register for a course demo, or visit the JustAcademy official website.